package cc.rengu.igas.bsps.core.service.base;

import cc.rengu.igas.bsps.common.constant.BspsTreeNodeConstant;
import cc.rengu.igas.bsps.common.enums.RespCodeEnum;
import cc.rengu.igas.bsps.core.model.UserSessionInfo;
import cc.rengu.igas.bsps.core.realize.UserPermissionCheckService;
import cc.rengu.igas.bsps.core.realize.impl.UserPermissionCheckServiceImpl;
import cc.rengu.igas.share.core.model.MchntInfo;
import cc.rengu.igas.share.core.realize.MchntService;
import cc.rengu.igas.share.core.realize.PublicService;
import cc.rengu.igas.share.core.realize.impl.MchntServiceImpl;
import cc.rengu.igas.share.core.realize.impl.PublicServiceImpl;
import cc.rengu.igas.share.core.realize.impl.RiskMonitorServiceImpl;
import cc.rengu.oltp.service.base.BizBaseService;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.enums.AcctTypeEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.BizResponse;
import cc.rengu.oltp.service.model.RiskMonitorInfo;
import cc.rengu.oltp.service.realize.RiskMonitorService;
import cc.rengu.oltp.utility.annotation.BIZ_AFTER;
import cc.rengu.oltp.utility.annotation.BIZ_BEFORE;
import cc.rengu.oltp.utility.annotation.BIZ_PROCESS;
import cc.rengu.oltp.utility.util.*;
import com.alibaba.fastjson.JSON;
import org.apache.commons.codec.binary.Base64;

/**
 * 线下支付服务基类
 * Created by 王成 on 2018/4/17.
 */
public abstract class PayService extends BizBaseService {

    @Override
    protected Object beforeBizProcess() throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        /* Step1：查找BIZ_BEFORE的注解*/
        invokeBizAnnoMethod(BIZ_BEFORE.class);
        String instId = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.INST_ID);
        String transAmt = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_AMT);
        if (StringUtil.isEmptyOrNull(transAmt)) {
            transAmt = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.ORDER_AMT);
        }
        String txnNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TXN_NUM);
        String msgSrcId = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.MSG_SRC_ID);
        /* Step 2：商户基础合法性检查 */
        String mchntNo = xmlTreeUtil.getXmlTreeStringValue(BspsTreeNodeConstant.MCHNT_NO);
        MchntService mchntService = new MchntServiceImpl();
        MchntInfo mchntInfo = mchntService.getMchntInfo(instId, mchntNo);
        if (null == mchntInfo) {
            rglog.error("获取商户信息失败,mchntNo:<{}>", mchntNo);
            throw new BizException(RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespCode(), RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespDesc());
        }
        String session = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SESSION);
        String userId = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.USER_ID);
        String channelId = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.CHANNEL_ID);
        String bizType = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.BIZ_TYPE);

        /* Step2：检查验签状态 */
        rglog.info("检查验签状态");
        String verifySignFlag = xmlTreeUtil.getXmlTreeStringValue(BspsTreeNodeConstant.VERIFY_SIGN_FLAG);
        rglog.info("验签标识：" + verifySignFlag);
        if (AppParamConstant.NO.equals(verifySignFlag)) {
            rglog.error("签名验证失败，交易码:<{}>", txnNum);
            if (StringUtil.isEmptyOrNull(session)) {
                rglog.error("session 为null");
                throw new BizException(RespCodeEnum.USER_NOT_LOGIN_OR_SESSION_IS_EXPIRED.getRespCode(), RespCodeEnum.USER_NOT_LOGIN_OR_SESSION_IS_EXPIRED.getRespDesc());
            }

            String sessionObjStr = RedisUtil.onceGet(session);
            if (sessionObjStr == null) {
                rglog.error("根据会话标识<{}>获取会话缓存失败", session);
                throw new BizException(RespCodeEnum.USER_NOT_LOGIN_OR_SESSION_IS_EXPIRED.getRespCode(), RespCodeEnum.USER_NOT_LOGIN_OR_SESSION_IS_EXPIRED.getRespDesc());
            }

            UserSessionInfo userSessionInfo = JSON.parseObject(sessionObjStr, UserSessionInfo.class);
            if (null == userSessionInfo) {
                rglog.error("根据会话标识<{}>获取会话缓存失败，转为UserSessionInfo失败。", session);
                throw new BizException(RespCodeEnum.USER_NOT_LOGIN_OR_SESSION_IS_EXPIRED.getRespCode(), RespCodeEnum.USER_NOT_LOGIN_OR_SESSION_IS_EXPIRED.getRespDesc());
            }

            throw new BizException(RespCodeEnum.VERIFY_SIGN_ERROR.getRespCode(), RespCodeEnum.VERIFY_SIGN_ERROR.getRespDesc());
        }

        rglog.info("验签成功");

        /* Step3：检查接口合法性 */
        PublicService publicService = new PublicServiceImpl();
        publicService.checkInputValidity(msgSrcId, txnNum);

        /* Step3:session检查 */
        UserPermissionCheckService userService = new UserPermissionCheckServiceImpl();
        //检查用户登录状态
        UserSessionInfo userSessionInfo = userService.checkUserLoginSessionStatus(instId, session, userId);
        //检查该用户角色是否有该交易权限
        if (!userService.checkNormalUserPermission(instId, userId, mchntNo, txnNum, channelId)) {
            rglog.error("用户权限校验失败", userId + ":" + txnNum);
            throw new BizException(RespCodeEnum.USER_NO_AUTHORITY.getRespCode(), RespCodeEnum.USER_NO_AUTHORITY.getRespDesc());
        }

//        /* 黑名单校验 */
//        mchntService.checkMchntBlackInfo(instId, mchntNo);

        /*校验产品权限*/
        boolean checkResult = mchntService.checkMchntAuth(instId, mchntNo, null, txnNum, bizType, AcctTypeEnum.ALL.getAcctType());
        if (!checkResult) {
            rglog.error("商户<{}>无此交易<{}>权限!", mchntNo, txnNum);
            throw new BizException(RespCodeEnum.MCHNT_NO_PERMISSION.getRespCode(), RespCodeEnum.MCHNT_NO_PERMISSION.getRespDesc());
        }

        /* Step4：交易处理前客户化 */
        return bizBeforeCust();
    }

    @Override
    protected BizResponse callBizService(Object request) throws Exception {
        /* Step1：查找BIZ_PROCESS的注解 */
        invokeBizAnnoMethod(BIZ_PROCESS.class);

        /* Step3：业务逻辑处理*/
        return bizProcessCust(request);
    }

    @Override
    protected void afterBizProcess(BizResponse response) throws Exception {
        /* Step1：业务调用后公共处理*/

        /* Step2：查找BIZ_AFTER的注解 */
        invokeBizAnnoMethod(BIZ_AFTER.class);

        /* Step3：业务调用后客户化处理 */
        bizAfterCust(response);
    }

    @Override
    protected RiskMonitorInfo getRiskMonitorInfo() {
        RiskMonitorInfo riskMonitorInfo = new RiskMonitorInfo();
        RiskMonitorService riskMonitorService = new RiskMonitorServiceImpl();
        riskMonitorInfo.setTransMonitor(riskMonitorService);
        return riskMonitorInfo;
    }

    /**
     * 业务处理前客户化处理
     *
     * @return 业务处理实体类
     */
    protected abstract Object bizBeforeCust() throws Exception;

    /**
     * 业务逻辑处理客户化处理
     *
     * @param request 业务处理前的返回实体类
     * @return 业务处理结果
     */
    protected abstract BizResponse bizProcessCust(Object request) throws Exception;

    /**
     * 业务处理后逻辑处理
     *
     * @param response 业务调用响应信息
     */
    protected abstract void bizAfterCust(Object response) throws Exception;

    private String descriptData(String sensitiveKey, String encData) throws Exception {
        //TODO 目前只支持AES PK5 ECB
        String algorithmType = "AES";
        if ("AES".equals(algorithmType)) {
            String descData = AESUtil.pkcs5EcbDecryptData(sensitiveKey, encData);
            return descData;
        } else {
            byte[] bEncData = Base64.decodeBase64(encData);
            byte[] descData = new byte[bEncData.length];
            int retCode = SM4Util.sms4(bEncData, bEncData.length, ByteUtil.hexStringToByte(sensitiveKey), descData, 0);
            if (retCode == 0) {
                for (int i = 0; i < descData.length; i++) {
                    if (descData[i] == 0) {
                        return new String(descData, 0, i);
                    }
                }
                return new String(descData);
            }
        }

        return null;
    }
}
